package main

import (
	"encoding/json"
	"fmt"
	"unsafe"
)

func main() {
	//定义浮点型
	//defineFloat()

	//定义数组
	//defineArray()

	//定义切片
	//defineSlice()

	//操作切片
	//sliceDemo()

	//定义Map
	//defineMap()

	//操作Map
	//mapDemo()

	//mapToSlice()

	//定义指针
	//definePointer()

	//操作指针
	//pointerDemo()

	//newFunction()

	//typeAlias() anonymous

	//defineStruct()

	//initStruct()

	//structRAM()

	//调用结构体的构造函数
	//person := structConstruct("星星有泪", 18)
	//fmt.Println(person) // &{星星有泪 18}
	//person.personToString() // name=星星有泪,age=18
	//person.setAge(28)
	//fmt.Println(person.age) //28

	//任意类型添加方法
	//var num myInt8 = 1
	//println(num.toString()) // 10

	//结构体之匿名字段
	//anonymousFiled()

	//结构体嵌套
	//nestedStruct()

	//结构体继承
	//var dog = &Dog{
	//	feet: 4,
	//	Animal: &Animal{
	//		name: "二狗子",
	//	},
	//}
	//dog.dogWang() // 二狗子汪汪汪
	//dog.animalMove() // 二狗子会动

	//structToJson(&Animal{
	//	"animal",
	//})

	structTag()
}

func structTag() {
	type Student struct {
		Id int8 `json:"id"`
	}
	var student Student = Student{
		1,
	}
	studentJosn, err := json.Marshal(student)
	if err == nil {
		fmt.Printf("%s\n", studentJosn) // {"id":1}
	}
}

func structToJson(dog *Animal) {
	dogJson, err := json.Marshal(dog)
	if err == nil {
		fmt.Printf("json:%s\n", dogJson)
	}
}

type Animal struct {
	Name string
}
type Dog struct {
	Feet int8
	*Animal
}

func (dog *Dog) dogWang() {
	fmt.Println(dog.Name + "汪汪汪")
}
func (animal *Animal) animalMove() {
	fmt.Println(animal.Name + "会动")
}

func nestedStruct() {
	type Class struct {
		id        uint8
		className string
	}

	type Student struct {
		id    uint8
		name  string
		Class Class
	}

	var class Class = Class{1, "一年级一班"}
	var student Student = Student{1, "星星有泪", class}
	fmt.Printf("%#v\n", student)
	// main.Student{id:0x1, name:"星星有泪", Class:main.Class{id:0x1, className:"一年级一班"}}
	fmt.Println(student.id)              // 1
	fmt.Println(student.Class.className) // 一年级一班

	type Teacher struct {
		id   uint8
		name string
		Class
	}
	var teacher Teacher
	teacher.id = 1
	teacher.className = "一年级一般"
	fmt.Println(teacher.Class.className) // 一年级一般
}

func anonymousFiled() {
	type Person struct {
		string
		uint8
	}
	var person Person
	person.string = "星星有泪"
	fmt.Println(person.string) // 星星有泪
}

type myInt8 int8

func (myint myInt8) toString() myInt8 {
	return myint * 10
}

type person struct {
	name string
	age  int8
}

func (p *person) setAge(age int8) {
	p.age = age
}

func (p person) personToString() {
	fmt.Printf("name=%s,age=%d \n", p.name, p.age)
}

func structConstruct(name string, age int8) *person {
	return &person{
		name,
		age,
	}
}

func structRAM() {
	var showRAM struct {
		a, b, c int8
	}
	fmt.Printf("a:%p\n", &showRAM.a) // a:0x140000b4002
	fmt.Printf("a:%p\n", &showRAM.b) // a:0x140000b4003
	fmt.Printf("a:%p\n", &showRAM.c) // a:0x140000b4004
}

func initStruct() {
	var fmtStruct string = "%#v\n"
	type person struct {
		name string
		age  int8
	}
	//初始化结构体
	var persion1 person
	fmt.Printf(fmtStruct, persion1) // main.person{name:"", age:0}

	//使用键值对初始化结构体
	var p2 person = person{
		name: "寒风凛凛",
		age:  18,
	}
	fmt.Printf(fmtStruct, p2) // main.person{name:"寒风凛凛", age:18}

	//对结构体指针进行键值对初始化
	var p3 = &person{
		name: "穷凶极恶",
		age:  38,
	}
	fmt.Printf(fmtStruct, p3) //&main.person{name:"穷凶极恶", age:38}

	//仅初始化部分成员属性
	var p4 person = person{name: "木无表情"}
	fmt.Printf(fmtStruct, p4) // main.person{name:"木无表情", age:0}

	//直接使用值初始化结构体
	var p5 = &person{"永恒之夜", 127}
	fmt.Printf(fmtStruct, p5) // &main.person{name:"永恒之夜", age:127}

	//空结构体：不占用内存空间
	var p6 struct{}
	fmt.Println(unsafe.Sizeof(p6)) //0
}

func defineStruct() {
	var fmtStruct string = "%#v \n"

	//定义结构体
	type person struct {
		name, city string
		age        int8
	}
	//实例化结构体
	var person1 person
	//访问结构体字段
	person1.name = "星星有泪"
	person1.age = 18
	fmt.Println(person1)           // {星星有泪  18}
	fmt.Printf(fmtStruct, person1) //main.person{name:"星星有泪", city:"", age:18}

	var person2 = new(person)
	person2.name = "乱舞狂刀"
	fmt.Printf(fmtStruct, person2) //&main.person{name:"乱舞狂刀", city:"", age:0}

	var person3 = &person{}
	person3.name = "随风起舞" // person3.name = "随风起舞"，其实在底层是 (*person).name = "随风起舞"，这是Go语言帮我们实现的语法糖
	(*person3).age = 19
	fmt.Printf(fmtStruct, person3) //&main.person{name:"随风起舞", city:"", age:19}

}

func typeAlias() {
	type newInt int8
	type intAlias = int8

	var a newInt
	var b intAlias
	fmt.Printf("newInt:%T---intAlias:%T", a, b)
	// newInt:main.newInt---intAlias:int8
}

func newFunction() {
	//声明指针变量
	var pointer *string
	fmt.Println(pointer) // <nil>
	//初始化指针变量，分配内存空间
	pointer = new(string)
	fmt.Println(pointer) // 0x14000010230
	//赋值
	*pointer = "1"
	fmt.Println(*pointer) // 1
}

func pointerDemo() {
	var strPtr *string
	fmt.Println(strPtr == nil) // true

}

func definePointer() {
	var num int8

	//获取变量 num 的内存地址
	var numPtr = &num
	fmt.Printf("num：%d---numPtr：%p", num, numPtr) // num：0---numPtr：0x14000018082
	println()
	//或者指针变量 numPtr 值
	var numPrtVal = *numPtr
	fmt.Printf("numPtr:%p---numPrtVal:%d", numPtr, numPrtVal) // numPtr:0x1400012a002---numPrtVal:0
}

func mapToSlice() {
	//元素为map类型的切片
	var mapSlice []map[string]int8 = make([]map[string]int8, 2, 10)
	fmt.Println(mapSlice) //[map[] map[]]

	//值为切片类型的map
	var map1 map[int8][]int8 = make(map[int8][]int8, 3)
	fmt.Println(map1)
}

func mapDemo() {
	var map1 map[string]int8 = make(map[string]int8)

	//添加元素，若key以存在则进行更新
	map1["A"] = 1

	//读取元素
	fmt.Println(map1["A"]) // 1

	//删除元素，会静默兼容Key不存在的case
	delete(map1, "A")
	delete(map1, "B")
	fmt.Println(map1) // map[]

	//读取一个不存在的Key，不会抛异常，会返回value对应数据类型的初始值
	fmt.Println(map1["A"]) // 0

	//判断一个Key是否存在
	if _, key := map1["A"]; !key {
		map1["A"] = 2
	}
	fmt.Println(map1["A"]) // 2

	//遍历Map，遍历时的元素顺序与添加键值对的顺序无关。
	//获取 key、value
	for key, value := range map1 {
		fmt.Printf("%s：%d", key, value)
		fmt.Println()
	} // A：2

	//仅获取 Key，不需要使用占位符
	for key := range map1 {
		fmt.Println(key)
	} // A

	//仅获取value，需要使用占位符
	for _, value := range map1 {
		fmt.Println(value)
	} // 2
}

func defineMap() {
	//声明Map一
	var map1 map[string]string = map[string]string{"1": "A"}
	fmt.Println(map1) //map[1:A]

	//声明Map二
	map2 := map[string]string{"2": "B"}
	fmt.Println(map2) //map[2:B]

	//声明Map三
	map3 := make(map[string]string)
	map3["3"] = "C"
	fmt.Println(map3) //map[3:C]

	//声明Map四
	var map4 map[string]string
	if map4 == nil {
		map4 = make(map[string]string, 1)
	}
	map4["4"] = "D"
	map4["5"] = "F"
	fmt.Println(map4) // map[4:D 5:F]
}

func sliceDemo() {
	slice := make([]int8, 0, 10)
	slicelen := len(slice) == 0
	//判断切片是否为空
	fmt.Println(slicelen) //ture

	//append添加元素
	slice = append(slice, 1)
	fmt.Println(slice) //[1]
	slice = append(slice, 2, 3)
	fmt.Println(slice) //[1 2 3]
	slice1 := []int8{4, 5}
	slice = append(slice, slice1...)
	fmt.Println(slice) //[1 2 3 4 5]

	//切片的赋值拷贝
	slice2 := slice
	slice2[0] = 100
	fmt.Println(slice) //[100 2 3 4 5]

	//切片的遍历，同数组
	slice2Len := len(slice2)
	for x := 0; x < slice2Len; x++ {
		fmt.Println(slice2[x])
	}

	//使用copy复杂切片
	slice3 := make([]int8, 5, 10)
	//将 slice 中元素复制到 slice3 中，注意目标 slice3 的容量或者长度要与 slice 相同
	copy(slice3, slice)
	//slice3[0] = 1
	fmt.Println(slice)  //[100 2 3 4 5]
	fmt.Println(slice3) //[1 2 3 4 5]

	//删除元素
	slice = append(slice[1:2], slice[2:]...)
	fmt.Println(slice) //[2 3 4 5]

	slice4 := make([]int8, 5, 10)
	var x int8
	for ; x < 10; x++ {
		slice4 = append(slice4, x)
	}
	fmt.Println(slice4) //[0 0 0 0 0 0 1 2 3 4 5 6 7 8 9]
}

func defineSlice() {
	//截取数组片段
	var arr1 [5]int8 = [5]int8{1, 2, 3}
	slice1 := arr1[0:2]
	fmt.Printf("s:%v len(slice):%v cap(slice):%v\n", slice1, len(slice1), cap(slice1))

	fmt.Println(arr1[2:]) //等同于arr1[2:len(arr1)]
	fmt.Println(arr1[:3]) //等同于arr1[0:3]
	fmt.Println(arr1[:])  //等同于arr1[0:len(arr1)]

	//切片再切片
	var slice2 = slice1
	println(slice2)

	//完整切片表达式
	var slice3 = arr1[:2:5]
	fmt.Printf("%v len：%v cap：%v\n", slice3, len(slice3), cap(slice3))

	//使用make构造切片
	slice4 := make([]int8, 2, 5)
	fmt.Printf("%v len:%v cap:%v\n", slice4, len(slice4), cap(slice4))
}

func defineArray() {
	//声明数组
	var arr1 [3]int
	arr1[0] = 1
	fmt.Println(arr1) //[1]

	//声明并初始化
	var arr2 [3]int = [3]int{1, 2, 3}
	arr3 := [3]int8{1, 2, 3}
	fmt.Println(arr2) //[1,2,3]
	fmt.Println(arr3) //[1,2,3]

	//
	arr4 := [...]int8{1}
	fmt.Println(arr4) //[1]
	arr5 := arr4
	arr5[0] = 5
	fmt.Println(arr5) //[5]

	//声明数组并初始化指定索引的值
	arr6 := [10]int8{9: 10}
	fmt.Println(arr6) //[0 0 0 0 0 0 0 0 0 10]

	//多维数组：每个 level 的数据类型必须是现同的，且必须指定每个 level 的长度
	arr8 := [1][2][3]int8{
		{
			{1, 2, 3},
		},
	}
	fmt.Println(arr8) //[[[1 2 3] [0 0 0]]]
}

func defineFloat() {
	var float1 float32 = 32e-2
	fmt.Println(float1)
	var float2 float32 = .37
	fmt.Println(float2)
}
